package com.jyniubi.gmail.wms.service.impl;

import com.alibaba.fastjson.JSON;
import com.jyniubi.gmail.common.exception.OrderException;
import com.jyniubi.gmail.wms.vo.SkuLockVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jyniubi.gmail.common.bean.PageResultVo;
import com.jyniubi.gmail.common.bean.PageParamVo;

import com.jyniubi.gmail.wms.mapper.WareSkuMapper;
import com.jyniubi.gmail.wms.entity.WareSkuEntity;
import com.jyniubi.gmail.wms.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuMapper, WareSkuEntity> implements WareSkuService {

    @Autowired
    private WareSkuMapper wareSkuMapper;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private static final String LOCK_PREFIX = "stock:lock:";

    private static final String KEY_PREFIX = "stock:info:";

    @Override
    public PageResultVo queryPage(PageParamVo paramVo) {
        IPage<WareSkuEntity> page = this.page(
                paramVo.getPage(),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageResultVo(page);
    }

    @Transactional
    @Override
    public List<SkuLockVo> checkAndLock(List<SkuLockVo> skuLockVoList,String orderToken) {
        if (CollectionUtils.isEmpty(skuLockVoList)){
            throw new OrderException("请选择要购买的商品");
        }
        // 遍历集合
        // 根据skuId查询ware_sku 验库存，库存不够抛出异常，库存够的话减去库存，加锁定库存，此操作需要分布式锁来保证原子性
        skuLockVoList.forEach(skuLockVo -> {
            this.checkLock(skuLockVo);
        });
        if (skuLockVoList.stream().anyMatch(skuLockVo -> !skuLockVo.getLock())) {
            skuLockVoList.stream().filter(SkuLockVo::getLock).collect(Collectors.toList()).forEach(skuLockVo -> {
                this.wareSkuMapper.unlock(skuLockVo.getWareSkuId(), skuLockVo.getCount());
            });
            return skuLockVoList;
        }
        // 为了将来支付之后的减库存 和 不支付之后的解锁库存，需要缓存锁定信息。orderToken:锁定信息
        this.redisTemplate.opsForValue().set(KEY_PREFIX + orderToken, JSON.toJSONString(skuLockVoList));
        this.rabbitTemplate.convertAndSend("ORDER.EXCHANGE","stock.ttl",orderToken);
        return null;
    }

    private void checkLock(SkuLockVo skuLockVo){
        RLock lock = this.redissonClient.getLock(LOCK_PREFIX + skuLockVo.getSkuId());
        lock.lock();
        // 验库存
        try {
            // 查询对应skuId的商品库存信息
            List<WareSkuEntity> wareSkuEntities = this.wareSkuMapper.check(skuLockVo.getSkuId(),skuLockVo.getCount());
            // 为空校验
            if (CollectionUtils.isEmpty(wareSkuEntities)){
                skuLockVo.setLock(false);
                return;
            }
            // 如果不为空就去第一条数据，大数据接口提供数据分析取代价最低的仓库发货，这里取第一个库存对应的仓库发货
            WareSkuEntity wareSkuEntity = wareSkuEntities.get(0);
            // 更新库存，锁库存
            if(this.wareSkuMapper.lock(wareSkuEntity.getId(),skuLockVo.getCount()) == 1 ){
                // 更新了一条，说明锁库存了
                skuLockVo.setLock(true);
                // 为了方便将来减库存，解锁库存
                skuLockVo.setWareSkuId(wareSkuEntity.getId());
            }else {
                skuLockVo.setLock(false);
            }

        } finally {
            // 解锁
            lock.unlock();
        }
    }

}